﻿#region Copyright (c) 2012-10, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using System.Globalization;
using System.Runtime.CompilerServices;
using NUnit.Framework;


namespace Amarok
{
	[TestFixture]
	public class Test_ExceptionFormatter
	{
		private class MyException : Exception
		{
			private readonly String mName;

			public String Name
			{
				get
				{
					return mName;
				}
			}

			public Version[] Versions
			{
				get;
				set;
			}

			public MyException(String message, String name)
				: base(message)
			{
				mName = name;
			}

			public MyException(String message, String name, Exception innerException)
				: base(message, innerException)
			{
				mName = name;
			}
		}


		// --- TESTS ---


		[Test]
		public void TestFormat_NullException()
		{
			var text = ExceptionFormatter.Format(null, CultureInfo.InvariantCulture);
			Assert.That(text, Is.Null);
		}

		[Test]
		public void TestFormat_SingleThrownException()
		{
			try
			{
				var exception = new MyException("File-Not-Found", "MyFile.txt");

				exception.Versions = new Version[] { 
					new Version("1.23"), 
					new Version("2.34"), 
					null, 
					new Version("4.32") 
				};

				throw exception;
			}
			catch (Exception e)
			{
				var text = ExceptionFormatter.Format(e, CultureInfo.InvariantCulture)
					.ToLowerInvariant();

				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter+myexception"));
				Assert.That(text, Is.StringContaining("file-not-found"));
				Assert.That(text, Is.StringContaining("myfile.txt"));
				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter"));
				Assert.That(text, Is.StringContaining("tests.amarok.common.dll"));
			}
		}

		[Test]
		public void TestFormat_SingleThrownException_CultureAwareData()
		{
			try
			{
				var exception = new MyException("File-Not-Found", "MyFile.txt");

				exception.Versions = new Version[] { 
					new Version("1.23"), 
					new Version("2.34"), 
					null, 
					new Version("4.32") 
				};

				exception.Data.Add("VALUE", 9.8);

				throw exception;
			}
			catch (Exception e)
			{
				var text = ExceptionFormatter.Format(e, CultureInfo.InvariantCulture)
					.ToLowerInvariant();

				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter+myexception"));
				Assert.That(text, Is.StringContaining("file-not-found"));
				Assert.That(text, Is.StringContaining("myfile.txt"));
				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter"));
				Assert.That(text, Is.StringContaining("tests.amarok.common.dll"));
				Assert.That(text, Is.StringContaining("9.8"));
			}
		}

		[Test]
		public void TestFormat_SingleNotThrownException()
		{
			var exception = new MyException("File-Not-Found", "MyFile.txt");

			var text = ExceptionFormatter.Format(exception, CultureInfo.InvariantCulture)
				.ToLowerInvariant();

			Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter+myexception"));
			Assert.That(text, Is.StringContaining("file-not-found"));
			Assert.That(text, Is.StringContaining("myfile.txt"));
			Assert.That(text, Is.StringContaining("<unavailable>"));
		}

		[Test]
		public void TestFormat_SingleThrownException_Data()
		{
			try
			{
				var exception = new MyException("File-Not-Found", "MyFile.txt");
				exception.Data["A"] = "aaa";
				exception.Data["B"] = "bbb";
				throw exception;
			}
			catch (Exception e)
			{
				String text = ExceptionFormatter.Format(e, CultureInfo.InvariantCulture)
					.ToLowerInvariant();

				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter+myexception"));
				Assert.That(text, Is.StringContaining("file-not-found"));
				Assert.That(text, Is.StringContaining("myfile.txt"));
				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter"));
				Assert.That(text, Is.StringContaining("tests.amarok.common.dll"));
				Assert.That(text, Is.StringContaining("a"));
				Assert.That(text, Is.StringContaining("aaa"));
				Assert.That(text, Is.StringContaining("b"));
				Assert.That(text, Is.StringContaining("bbb"));
			}
		}

		[Test]
		public void TestFormat_ThrownExceptionWithInnerExceptions()
		{
			try
			{
				_ThrowAnException();
			}
			catch (Exception e)
			{
				var text = ExceptionFormatter.Format(e, CultureInfo.InvariantCulture)
					.ToLowerInvariant();

				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter+myexception"));
				Assert.That(text, Is.StringContaining("system.nullreferenceexception"));
				Assert.That(text, Is.StringContaining("system.argumentexception"));
				Assert.That(text, Is.StringContaining("file not found"));
				Assert.That(text, Is.StringContaining("can't access file"));
				Assert.That(text, Is.StringContaining("myfile.txt"));
				Assert.That(text, Is.StringContaining("amarok.test_exceptionformatter"));
				Assert.That(text, Is.StringContaining("_throwanexception"));
				Assert.That(text, Is.StringContaining("_throwansecondexception"));
				Assert.That(text, Is.StringContaining("tests.amarok.common.dll"));
			}
		}

		private static void _ThrowAnException()
		{
			try
			{
				_ThrowAnSecondException();
			}
			catch (Exception e)
			{
				throw new ArgumentException("invalid filename", e);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void _ThrowAnSecondException()
		{
			throw new MyException("File not found", "Myfile.txt",
				new NullReferenceException("Can't access file", null));
		}

		[Test]
		public void TestFormat_ParamName_Is_Output_Twice()
		{
			var message = Helper.FormatException(
				new ArgumentException("MSG", "PARAM")
			);

			Assert.That(message, Is.StringContaining(
				"ArgumentException.ParamName = \"PARAM\""));

			Assert.That(message, Is.Not.StringContaining(
				"ArgumentException.ParamName = {"));
		}

	}
}

#endif
